package com.quick.common.utils.file;

import com.quick.common.exception.ServiceException;
import com.quick.common.utils.StringUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.time.DateFormatUtils;;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

/**
 * 文件上传工具类
 *
 * @Author: 吃素不吃肉
 * @Date: Tue Jul 25 14:14:44 CST 2023
 */
public class FileUploadUtils {
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 默认上传的地址
     */
    private static String DEFAULT_BASE_DIR = "." + File.separator + "profile";
    /**
     * 资源映射路径 前缀
     */
    public static final String RESOURCE_PREFIX = "/profile";

    public static void setDefaultBaseDir(String defaultBaseDir) {
        FileUploadUtils.DEFAULT_BASE_DIR = defaultBaseDir;
    }

    public static String getDefaultBaseDir() {
        return DEFAULT_BASE_DIR;
    }

    /**
     * 获取导入上传路径
     */
    public static String getImportPath() {
        return getDefaultBaseDir() + File.separator + "import";
    }

    /**
     * 获取头像上传路径
     */
    public static String getAvatarPath() {
        return getDefaultBaseDir() + File.separator + "avatar";
    }

    /**
     * 获取下载路径
     */
    public static String getDownloadPath() {
        return getDefaultBaseDir() + File.separator + "download";
    }

    /**
     * 获取上传路径
     */
    public static String getUploadPath() {
        return getDefaultBaseDir() + File.separator + "upload";
    }

    /**
     * 以默认配置进行文件上传
     *
     * @param file 上传的文件
     * @return 文件名称
     */
    public static String upload(MultipartFile file) {
        return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
    }

    /**
     * 根据文件路径上传
     *
     * @param baseDir 相对应用的基目录
     * @param file    上传的文件
     * @return 文件名称
     */
    public static String upload(String baseDir, MultipartFile file) {
        return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
    }

    /**
     * 文件上传
     *
     * @param baseDir          相对应用的基目录
     * @param file             上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     */
    public static String upload(String baseDir, MultipartFile file, String[] allowedExtension) {
        int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new ServiceException(StringUtils.format("上传文件名长度超过{}限制！", DEFAULT_FILE_NAME_LENGTH));
        }
        assertAllowed(file, allowedExtension);
        String fileName = extractFilename(file);
        String absPath = getAbsolutePathFile(baseDir, fileName).getAbsolutePath();
        try {
            file.transferTo(Paths.get(absPath));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return getPathFileName(baseDir, fileName);

    }

    /**
     * 编码文件名
     *
     * @param file 文件
     * @return 返回系统生成的文件名
     */
    public static String extractFilename(MultipartFile file) {
        return StringUtils.format("{}/{}_{}.{}", DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.format(new Date()),
                FilenameUtils.getBaseName(file.getOriginalFilename()), UUID.randomUUID().toString(), getExtension(file));
    }

    /**
     * 获取绝对路径文件
     *
     * @param uploadDir 上传文件目录
     * @param fileName  文件名
     * @return 绝对路径文件
     */
    public static File getAbsolutePathFile(String uploadDir, String fileName) {
        File desc = new File(uploadDir + File.separator + fileName);
        if (!desc.exists()) {
            if (!desc.getParentFile().exists()) {
                desc.getParentFile().mkdirs();
            }
        }
        return desc;
    }

    /**
     * 获取路径文件名
     *
     * @param uploadDir 上传文件目录
     * @param fileName  文件名
     * @return 完整路径
     */
    public static String getPathFileName(String uploadDir, String fileName) {
        int dirLastIndex = getDefaultBaseDir().length() + 1;
        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
        return RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     */
    public static void assertAllowed(MultipartFile file, String[] allowedExtension) {
        long size = file.getSize();
        if (size > DEFAULT_MAX_SIZE) {
            throw new ServiceException(StringUtils.format("上传文件大小超过{}限制！", DEFAULT_MAX_SIZE / 1024 / 1024));
        }
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
            throw new ServiceException(StringUtils.format("文件[{}]格式[{}]不正确，请上传{}格式！", fileName, extension, Arrays.toString(allowedExtension)));
        }
    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension        文件类型
     * @param allowedExtension 允许的文件类型
     * @return true 允许，false 不允许
     */
    public static boolean isAllowedExtension(String extension, String[] allowedExtension) {
        for (String str : allowedExtension) {
            if (str.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
        }
        return extension;
    }
}
